package com.tanhua.server.service;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.api.R;
import com.tanhua.autoconfig.template.AipFaceTemplate;
import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.utils.Constants;
import com.tanhua.dubbo.api.*;
import com.tanhua.model.domain.User;
import com.tanhua.model.domain.UserInfo;
import com.tanhua.model.mongo.Focus;
import com.tanhua.model.mongo.UserLike;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.UserInfoVo;
import com.tanhua.model.vo.XzjVo;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.server.interceptor.UserHolder;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.lang.reflect.Array;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class UserInfoService {

    @DubboReference
    private FocusApi focusApi;

    @DubboReference
    private UserLikeApi userLikeApi;

    @DubboReference
    private RecommendUserApi recommendUserApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private VisitorsApi visitorsApi;

    @DubboReference
    private UserApi userApi;

    @Autowired
    private UserService userService;

    @Autowired
    private OssTemplate ossTemplate;

    @Autowired
    private AipFaceTemplate aipFaceTemplate;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;


    public void save(UserInfo userInfo) {
        userInfoApi.save(userInfo);
    }

    //更新用户头像
    public void updateHead(MultipartFile headPhoto, Long id) throws IOException {
        //1、将图片上传到阿里云oss
        String imageUrl = ossTemplate.upload(headPhoto.getOriginalFilename(), headPhoto.getInputStream());
        //2、调用百度云判断是否包含人脸
        boolean detect = aipFaceTemplate.detect(imageUrl);
        //2.1 如果不包含人脸，抛出异常
        if (!detect) {
            throw new BusinessException(ErrorResult.faceError());
        } else {
            //2.2 包含人脸，调用API更新
            UserInfo userInfo = new UserInfo();
            userInfo.setId(id);
            userInfo.setAvatar(imageUrl);
            userInfoApi.update(userInfo);
        }
    }

    //根据id查寻
    public UserInfoVo findById(Long id) {
        UserInfo userInfo = userInfoApi.findById(id);

        UserInfoVo vo = new UserInfoVo();

        BeanUtils.copyProperties(userInfo, vo); //copy同名同类型的属性

        if (userInfo.getAge() != null) {
            vo.setAge(userInfo.getAge().toString());
        }

        return vo;
    }

    //更新
    public void update(UserInfo userInfo) {
        userInfoApi.update(userInfo);
    }

    public void fansLike(Long uid) {
        //拿到用户id
        Long userId = UserHolder.getUserId();
        //构造保存的对象
        Focus focus = new Focus();
        focus.setCreateDate(new SimpleDateFormat("yyyyMMdd").format(new Date()));
        focus.setUserId(uid);
        focus.setToUserId(userId);
        //保存
        focusApi.save(focus);
        //保存到redis中
        redisTemplate.opsForHash().put(Constants.FOCUS_USER_KEY + uid, userId.toString(), "1");
    }

    public void removeLike(Long uid) {
        //拿到用户id
        Long userId = UserHolder.getUserId();
        //删除
        focusApi.delete(uid, userId);
        //从redis中删除
        redisTemplate.opsForHash().get(Constants.FOCUS_USER_KEY + uid, userId.toString());
    }

    public PageResult friendsType(Integer page, Integer pagesize, String nickname, Integer type) {
        //获取用户id
        Long userId = UserHolder.getUserId();
        //用户集合
        Map<Long, UserInfo> userInfoMap = new HashMap<>();
        //用户id
        Set<Long> userIds = new HashSet<>();
        //所有的用户
        List<Long> focus = new ArrayList<>();

        if (type == 1) {
            //互相关注
            ArrayList<Long> longs = new ArrayList<>();
            //根据用户id在redis中拿到用户id
            Map<Object, Object> entries = redisTemplate.opsForHash().entries(Constants.FOCUS_USER_KEY + userId);
            Set<Object> objects = entries.keySet();
            for (Object object : objects) {
                Long id = Long.valueOf(object.toString());
                longs.add(id);
            }
            //判断是否存在互相关注
            for (Long aLong : longs) {
                Object o = redisTemplate.opsForHash().get(Constants.FOCUS_USER_KEY + aLong, userId.toString());
                if (o != null) {
                    //互相关注
                    focus.add(aLong);
                }
            }
        } else if (type == 2) {
            //我关注
            Map<Object, Object> entries = redisTemplate.opsForHash().entries(Constants.FOCUS_USER_KEY + userId);
            Set<Object> objects = entries.keySet();
            for (Object object : objects) {
                Long id = Long.valueOf(object.toString());
                focus.add(id);
            }

        } else if (type == 3) {
            //粉丝
            //查表
            focus = focusApi.getByUserId(userId);
        } else if (type == 4) {
            //谁看过我
            //拿到访客的用户id
            List<Visitors> visitorsList = visitorsApi.getVisitorsByUserId(userId);
            focus = CollUtil.getFieldValues(visitorsList, "visitorUserId", Long.class);
        }

        //构造返回的对象
        PageResult result = new PageResult();
        //总条数
        int size = focus.size();
        if (focus == null || size == 0) {
            result.setItems(new ArrayList<>());
            return result;
        }

        //拿到互相关注的用户的id
        userInfoMap = userInfoApi.getByIds(page, pagesize, nickname, focus);
        userIds = userInfoMap.keySet();
        //是否喜欢Ta
        Map<Long, Boolean> alreadyLoveMap = userLikeApi.alreadyLove(userId, userIds);
        //匹配度
        Map<Long, Integer> matchRateMap = recommendUserApi.matchRate(userId, userIds);

        List<XzjVo> xzjVoList = new ArrayList<>();
        //赋值
        Collection<UserInfo> values = userInfoMap.values();
        for (UserInfo userInfo : values) {
            XzjVo xzjVo = new XzjVo();
            //用户详细信息
            BeanUtils.copyProperties(userInfo, xzjVo);

            //匹配度
            Integer matchRate = matchRateMap.get(userInfo.getId());
            if (matchRate == null) {
                Random random = new Random();
                matchRate = random.nextInt(9) + 90;
            }
            xzjVo.setMatchRate(matchRate);

            //是否喜欢Ta
            Boolean aBoolean = alreadyLoveMap.get(userInfo.getId());
            if (aBoolean == null) {
                aBoolean = false;
            }
            xzjVo.setAlreadyLove(aBoolean);
            //添加进集合
            xzjVoList.add(xzjVo);
        }
        result.setCounts(Long.valueOf(size));
        result.setItems(xzjVoList);
        result.setPage(page);
        result.setPagesize(pagesize);
        result.setPage((int) Math.ceil(result.getCounts() * 1.0 / pagesize));
        return result;
    }
    //更新用户头像
    public void updateHeadPhoto(MultipartFile headPhoto, Long userId) throws IOException {
        //查询用户原头像数据，并且调用oss进行删除
        UserInfo info = userInfoApi.findById(userId);
        String avatar = info.getAvatar();
        ossTemplate.delete(avatar);
        //将图片上传到阿里云oss
        String imageUrl = ossTemplate.upload(headPhoto.getOriginalFilename(), headPhoto.getInputStream());
        //调用百度云判断是否包含人脸
        boolean detect = aipFaceTemplate.detect(imageUrl);
        //如果不包含人脸，抛出异常
        if (!detect) {
            throw new BusinessException(ErrorResult.faceError());
        } else {
            //包含人脸，调用API更新
            info.setId(userId);
            info.setAvatar(imageUrl);
            userInfoApi.update(info);
        }
    }

    //发送短信验证码
    public void sendCode(Long loginId) {
        //根据当前用户Id查询用户信息，取出当前用户电话号码
        User user = userApi.findById(loginId);
        String phoneNum = user.getMobile();
        //调用方法发送验证码
        userService.sendMsg(phoneNum);
    }


    //验证码校验
    public Map<String, Boolean> loginVerification(String verificationCode, String mobile) {
        //获取redis中储存的验证码
        String redisCode = redisTemplate.opsForValue().get("CHECK_CODE_" + mobile);
        //对验证码进行校验（验证码是否存在，是否和输入的验证码一致）
        Map<String, Boolean> map = new HashMap<>();
        if (StringUtils.isEmpty(redisCode) || !redisCode.equals(verificationCode)) {
            //验证码无效
            map.put("verification", false);
            return map;
        }
        //删除redis中的验证码
        redisTemplate.delete("CHECK_CODE_" + mobile);
        map.put("verification", true);
        return map;
    }

    public Map<String, Integer> counts(Long userId) {
        //获取喜欢用户的人数
        Long fanCount = userLikeApi.count(userId);
        //获取当前用户喜欢的人数
        Set<String> members = redisTemplate.opsForSet().members(Constants.USER_LIKE_KEY + userId);
        Integer loveCount = 0;

        if (members != null && members.size() != 0) {
            loveCount = members.size();
        }
        //获取相互喜欢的人数
        Integer eachLoveCount = loveEachOther(UserHolder.getUserId());

        //组装数据
        Map<String, Integer> map = new HashMap<>();
        map.put("eachLoveCount", eachLoveCount);
        map.put("loveCount", loveCount);
        map.put("fanCount", Math.toIntExact(fanCount));
        return map;
    }

    //获取相互喜欢的数量
    public Integer loveEachOther(Long userId) {
        Integer eachLoveCount = 0;
        Set<String> likes = redisTemplate.opsForSet().members(Constants.USER_LIKE_KEY + userId);
        if (likes != null && likes.size() != 0) {
            for (String like : likes) {
                Boolean result = isLike(Long.valueOf(like), userId);
                if (result) {
                    eachLoveCount++;
                }
            }
        }
        return eachLoveCount;
    }

    public Boolean isLike(Long userId,Long likeUserId) {
        String key = Constants.USER_LIKE_KEY+userId;
        return redisTemplate.opsForSet().isMember(key,likeUserId.toString());
    }


}
